
import { UtilsHelper } from "utils/position/UtilsHelper";
import { StructureEntity, entity_memory_cache } from "../StructureEntity";
import { LabConfig } from "./labLayout";
import { PositionHelper } from "utils/position/PositionHelper";
 
 
/**
 * lab模块
 */
export   class LabEntity<T extends ILabMemory=ILabMemory,V extends IRoomModuleInitializer=IRoomModuleInitializer>  extends StructureEntity<T,V>  
{
    @entity_memory_cache()
    protected labState!:{[key:string]:0|1 }; //    0:合成 1:强化

    @entity_memory_cache()      // boost任务的强化列表
    private minerialRecord!:Record<MineralBoostConstant,Required<IBoostConfig>>;
    @entity_memory_cache()      // 正在强化的任务列表
    private boostTasks!:string[];   
    /**
     * ---------------------------------------------------------------------------------------------
     * 继承抽象方法
     */
    protected initNodeMemory()
    {
        super.initNodeMemory();
        if(!this.labState)
        {
            this.resetLabState()
        }
        if(!this.boostTasks)
        {
            this.boostTasks=[];
        }
        if(!this.minerialRecord)
        {
            this.minerialRecord={}as any;
        }
    }
    /**
     * 所有lab复位为reaction lab
     */
    public resetLabState()
    {
        this.labState={};
        for(const item of LabConfig.ReactionLabPos)
        {
            this.labState[`${item.x}_${item.y}`]= 0;
        }
        for(const item of LabConfig.BaseLabPos)
        {
            this.labState[`${item.x}_${item.y}`]= 0;
        }
    }
    public updateMemory(): void 
    {
        // throw new Error("Method not implemented.");
    }

    private IsReactionLab(pos:IFVector2)
    {
        return this.labState [`${pos.x}_${pos.y}`] ===0;
    }
    public   isBaseEmpty()
    {
        return _.filter(this.BaseLabs(),e=>e.mineralType).length ==0;
    }
    public getContainer()
    {
        return this.getStructuresByRelative(STRUCTURE_CONTAINER,LabConfig.ContainerPos,this.BasePosition);
    }
    /*
    反应相关
    */
    public BaseLabs():StructureLab[]
    {
        // 被占用了则不能反应
        for(const e of LabConfig.BaseLabPos)
        {
            if(this.getLabState(e))
            {
                return []
            }
        }
        const ids = this.getStructuresByRelative(STRUCTURE_LAB,LabConfig.BaseLabPos,this.BasePosition);
        return this.getStructureObjects(ids);
    }
    public  Labs():StructureLab[]
    {

        const allpos = LabConfig.BaseLabPos.concat(LabConfig.ReactionLabPos);
        const ids =  this.getStructuresByRelative(STRUCTURE_LAB,allpos,this.BasePosition);
        return this.getStructureObjects(ids);
    }
    /**
     * 获取反应的Labs 这个会和Boost的lab互斥
    */
     public ReactionLabs():StructureLab[]
    {
        const labs:StructureLab[] = [];
        for(const pos of LabConfig.ReactionLabPos)
        {
            if(!this.IsReactionLab(pos))
            {
                continue;
            }
            const cache = this.getStructureByRelative(STRUCTURE_LAB,pos,this.BasePosition);
            const lab = cache?Game.getObjectById(cache?.id):undefined;
            if( lab  )
            {
                labs.push(lab);
            }
        }
        //global.Log.Info(`ReactionLabs count:${labs.length}`);
        return labs;
    }

    public unBoostPosition():RoomPosition
    {
        return PositionHelper.Create({x:this.BasePosition.x+1,y:this.BasePosition.y+1,roomName:this.roomName})
    }

    public unBoostLabs():StructureLab[]
    {
        const labs =  this.getStructuresByRelative (STRUCTURE_LAB,LabConfig.unBoostLabPos,this.BasePosition);
        return this.getStructureObjects(labs,e=>e.cooldown<10);
    }
     /**
     * 获取反应的Labs 这个会和Boost的lab互斥
    */
    public BoostLabs():StructureLab[]
    {
        const labs:StructureLab[] = [];
        const allLabConfig = LabConfig.ReactionLabPos.concat(LabConfig.BaseLabPos);
        for(const pos of allLabConfig)
        {
            if(this.IsReactionLab(pos))
            {
                continue;
            }
            const cache = this.getStructureByRelative(STRUCTURE_LAB,pos,this.BasePosition);
            const lab = cache?Game.getObjectById(cache?.id):undefined;
            if( lab   )
            {
                labs.push(lab);
            }
        }
        
        return labs;
    }
    private getLabState(e:IFVector2)
    {
        return this.labState[`${e.x}_${e.y}`]
    }


 
    /**
     * *************************************************************************************
     * boost 相关函数
    */
   /**
    * 根据当前状态决定每次boost的个数. 防守状态有就boost 。 小队出击状态。等待多个一起boost
    * @param task 
    * @returns 
    */
    public activeBoostTask(task:ITask<ILabTaskData<"boost">>):boolean
    {
        for(const e of task.data.arg.res)
        {
            if(this.minerialRecord[e.resource] && (this.minerialRecord[e.resource].amount +e.amount)>3000)
            {
                return false;
            }
        }
        if(!this.boostTasks.includes( task.id))
        {
            
            this.boostTasks.push(task.id);
           
            const tasks = this.boostTasks.map(e=> this.room.findTaskById(e,"boost")) as ITask<ILabTaskData<"boost">>[];
            this.updateAllocBoostLab(tasks);
        }
       
        // 添加成功.则更新材料列表
        return true;
    }


    public allocBoostLab(task:IBoostTask)
    {
        if(!task.res)
        {
            return false;
        }
        let length = task.res.length;
        for(const key in this.labState  )
        {
            this.labState [key] = 1;
            length--;
            if(length<=0)
            {
                break;
            }
        }
        return true;
    }
    public allocBoostLabByNum(num:number)
    {
        const _this = this;

        const allocLab = (pos:IFVector2[],num:number)=>
        {
            for(const e of pos)
            {
                const labid = _this.getStructureByRelative(STRUCTURE_LAB,e,_this.BasePosition);
                const lab = labid?Game.getObjectById(labid?.id):null;
                if(lab && lab.isActive())
                {
                    this.labState[`${e.x}_${e.y}`] = 1;
                    num--;
                    if(num<=0)
                    {
                        break;
                    }
                }
            }
            return num
        }
        let leftnum = allocLab(LabConfig.ReactionLabPos,num);
        if(leftnum >0)
        {
            leftnum = allocLab(LabConfig.BaseLabPos,leftnum);
            // 中止lab合成任务
        }

        return leftnum== 0;
    }

    public unBoostContainer()
    {
        const cache = this.getStructureByRelative(STRUCTURE_CONTAINER,{x:1,y:1},this.BasePosition);
        return cache?Game.getObjectById(cache?.id):null;
    }
    /**
     * 重新分配lab
     */
    public reallocLab()
    {
        const tasks = this.boostTasks.map(e=> this.room.findTaskById(e,"boost")) as ITask<ILabTaskData<"boost">>[];
        this.updateAllocBoostLab(tasks);
    }
    public updateAllocBoostLab(Tasks:ITask<ILabTaskData<"boost">>[])
    {
        this.minerialRecord = this.getTaskRequireMinerials(Tasks) as Record<MineralBoostConstant,Required<IBoostConfig>>;
        const minerialcount = Object.keys(this.minerialRecord).length;

        let boostlabs = this.BoostLabs();
        if(boostlabs.length<minerialcount)
        {
            this.allocBoostLabByNum(minerialcount);
            boostlabs = this.BoostLabs();
        }
        this.log("info",`分配的lab 数量为:${boostlabs.length}  需要的lab数量为:${minerialcount}`);
        if(minerialcount <= boostlabs.length && boostlabs.length>0)
        {
            // BoostLab分配成功
            // 对lab进行划分
            for(const lab of boostlabs)
            {
                // 存在化合物的找匹配的进行分配
                if(lab.mineralType)
                {
                    if(this.minerialRecord[lab.mineralType as MineralBoostConstant])
                    {
                        this.minerialRecord[lab.mineralType as MineralBoostConstant].lab = lab.id;
                    }
                    else
                    {

                    }
                }
            }
            for(const lab of boostlabs)
            {
                if(!lab.mineralType)
                {
                    const boostconfig = _.find(this.minerialRecord,e=>!e.lab);
                    if(boostconfig)
                    {
                        boostconfig.lab = lab.id;
                    }
                    else
                    {
                    }
                }
            }
        };
    }
    
    private getTaskRequireMinerials(Tasks:ITask<ILabTaskData<"boost">>[])
    {
        const minerialRecord:Record<MineralBoostConstant,IBoostConfig>={} as any;
       
        for(let i=0;i<Tasks.length;i++)
        {

            const task = Tasks[i].data;
            if(this.isvalidTask(task,minerialRecord))
            {
                for(const e of task.arg.res )
                {
                    if(minerialRecord[e.resource])
                    {
                        minerialRecord[e.resource].amount+=e.amount;
                    }
                    else
                    {
                        minerialRecord[e.resource]={amount:e.amount};
                    }
                }
            }
        }
        return minerialRecord;
    }
    private isvalidTask(task:ILabTaskData<"boost">,minerialRecord:Record<MineralBoostConstant,IBoostConfig>)
    {
        for(const e of task.arg.res )
        {
            if(minerialRecord[e.resource])
            {

                if( minerialRecord[e.resource].amount+e.amount>3000)
                {
                    return false;
                }

            }
            else
            {
                if(e.amount>3000)
                {
                    return false;
                }
            }
        }
        return true;
    }
     /**
     * lab中存在不需要的化合物,且每种化合物只能存在一个lab上
    */
    public isLabsShouldClear()
    {
        const boostlabs = this.BoostLabs();
        const minerial_record:Record<string,number>={};
        for(const lab of boostlabs)
        {
            // 存在化合物的找匹配的进行分配
            if(lab.mineralType)
            {
                if(!this.minerialRecord[lab.mineralType as MineralBoostConstant])
                {
                    return true;
                }
                if(minerial_record[lab.mineralType])
                {
                    return true;
                }
                else
                {
                    minerial_record[lab.mineralType]=1;
                }
            }
        }
        return false;
    }
    /**
     * 强化资源是否准备好
     * @returns 
     */
    public isLabResourceReady():OK|-1|-2
    {
        for(const key in this.minerialRecord)
        {
            const configitem = this.minerialRecord[key as MineralBoostConstant];
            const lab = Game.getObjectById(configitem.lab as Id<StructureLab>);
            if(lab)
            {
                if(!lab.mineralType)
                {
                    return -1;
                }
                if(lab.store.getUsedCapacity(lab.mineralType)<configitem.amount)
                {
                    return -1;
                }
                if(lab.store.getUsedCapacity(RESOURCE_ENERGY)<Math.ceil(configitem.amount*2/3))
                {
                    return -1;
                }
            }
            else
            {
                
                global.Log.Warning(`${key} 未设置 boost lab 或者lab不存在!`);
                return -2;
            }
        }
        return OK;
    }

    public inquireMinerialLab(minerial:MineralBoostConstant):Id<StructureLab>
    {
        return this.minerialRecord[minerial].lab;
    }

    /**
     * boost完成之后数据清空
     */
    public endBoost()
    {
       
        const memory = this.getNodeMemory();
        memory.boostTasks=[];
        memory.minerialRecord={} as any;
        for(const key in memory.labState)
        {
            memory.labState[key] = 0;
        }
    }
}
